import React, { useState, memo } from 'react';

import styles from './useMemo.css';

function useMemo(fn: Function, deps: any[] = []) {
  const [state, setState] = useState(() => ({ value: fn(), deps }));
  if (state.deps.length != deps.length) {
    const value = fn();
    setState({ value, deps });
    return value;
  }
  const oldDeps = state.deps;
  if (deps.find((dep, idx) => dep !== oldDeps[idx])) {
    const value = fn();
    setState({ value, deps });
    return value;
  }
  return state.value;
}

function ABigChild({ a, b }: any) {
  console.log('ABigChild rendered');
  return (
    <pre className={styles.alignLeft}>{JSON.stringify({ a, b }, null, 2)}</pre>
  );
}

const ABigChildMemo = memo(ABigChild);

/**
 * 可以缓存计算值，也可以缓存 Element(提前或者在jsx中)，也可以源头上使用 memo(FC)
 */
export default function UseMemo() {
  const [state, setState] = useState(0);
  const [state2, setState2] = useState(0);
  const doubleState = useMemo(() => state * 2, [state]);

  // 经测试，编辑保存后，dev热加载后，所有 hook 状态重新初始化了
  console.log({ state, state2 });

  // 子组件只依赖于 state，不依赖 state2 重新渲染，这个作为主要的性能优化
  const memorizedBigChild = useMemo(() => <ABigChild a={state} b="fixed" />, [
    state,
  ]);
  return (
    <div className={styles.normal}>
      <h1>Page useMemo</h1>
      <div>
        state = {state} doubled = {doubleState} state2 = {state2}
      </div>
      <button onClick={() => setState(Math.ceil(Math.random() * 10))}>
        change state
      </button>
      <button onClick={() => setState2(Math.ceil(Math.random() * 10))}>
        change state2
      </button>
      {memorizedBigChild}
      <hr />
      {/* 也可以内嵌在 jsx 中进行优化，防止大的子组件随父级组件重新渲染自己也联动重新渲染 */}
      {useMemo(
        () => (
          <ABigChild a={state} b="fixed" />
        ),
        [state],
      )}
      <hr />
      <ABigChildMemo a={state} b="fixed" />
    </div>
  );
}
